在R中如何将字符串识别为变量名

79

相关问题:R中字符串作为变量引用
可能相关:连接表达式以对数据框进行子集操作


根据评论请求,我简化了问题。以下是一些示例数据。

dat <- data.frame(num=1:10,sq=(1:10)^2,cu=(1:10)^3)
set1 <- subset(dat,num>5)
set2 <- subset(dat,num<=5)

现在,我想从这些数据中制作一个气泡图。我有一个更复杂的数据集,有三种以上的颜色和复杂的子集,但我可以像这样做:

symbols(set1$sq,set1$cu,circles=set1$num,bg="red")
symbols(set2$sq,set2$cu,circles=set2$num,bg="blue",add=T)

我希望能够像这样使用for循环:
colors <- c("red","blue")
sets <- c("set1","set2")
vars <- c("sq","cu","num")

for (i in 1:length(sets)) {
   symbols(sets[[i]][,sq],sets[[i]][,cu],circles=sets[[i]][,num],
   bg=colors[[i]],add=T)
}    

我知道您可以使用变量来指定列(例如var="cu"; set1[,var]),但我想知道如何使用变量来指定数据框本身(以及另一个变量来评估列)。
更新:在r-bloggers上看到了这篇文章,其中有这个例子。
x <- 42
eval(parse(text = "x"))
[1] 42

我现在能够做到这样的事情:
eval(parse(text=paste(set[[1]],"$",var1,sep="")))

在处理这个问题时,我发现以下内容并不等价:

在对此进行尝试时,我发现以下内容并不等价:

vars <- data.frame("var1","var2")
eval(parse(text=paste(set[[1]],"$",var1,sep="")))
eval(parse(text=paste(set[[1]],"[,vars[[1]]]",sep="")))

我实际上需要做这个:


eval(parse(text=paste(set[[1]],"[,as.character(vars[[1]])]",sep="")))

更新2:上述操作可以输出值,但无法绘制。我不能执行以下操作:
for (i in 1:length(set)) {
symbols(eval(parse(text=paste(set[[i]],"$",var1,sep=""))),
       eval(parse(text=paste(set[[i]],"$",var2,sep=""))),
       circles=paste(set[[i]],".","circles",sep=""),
       fg="white",bg=colors[[i]],add=T)
}

我收到了“无效符号坐标”的错误提示。我检查了set[[1]]的类别,发现它是一个因子(fator)。如果我执行is.numeric(as.numeric(set[[1]])),会得到TRUE的结果。即使在eval语句之前加入这个操作,我仍然会收到同样的错误提示。但是奇怪的是,我可以执行以下操作:

set.xvars <- as.numeric(eval(parse(text=paste(set[[i]],"$",var1,sep=""))))
set.yvars <- as.numeric(eval(parse(text=paste(set[[i]],"$",var2,sep=""))))
symbols(xvars,yvars,circles=data$var3)

为什么存储为变量和在符号函数中执行时行为不同?

2
你能否重新用实际问题重写你的问题?标题中有一个问题,但没有明确说明你要做什么。 - Maiasaura
1
如果您使用 dput 给我们提供一些示例数据,那将非常有帮助。 - Maiasaura
@Maiasaura:如果我的修改更清晰,请告诉我。我真的不认为数据是必要的,但如果你真的需要它,我会想出一些例子。 - Hendy
4
var1=42; foo="var1"; get(foo); 是另一种通过字符串获取变量的方法。 - Maiasaura
可能是从字符变量获取数据框的重复问题。 - Thomas
显示剩余2条评论
6个回答

55
你已经找到了一个答案,即eval(parse())。你还可以研究do.call(),这通常更容易实现。同时要记住有用的as.name()工具,用于将字符串转换为变量名。

22
尝试将粘贴的字符串转换为变量时,eval(as.name(paste())) 对我有用,谢谢! - chimeric
5
我有一个复杂的结构(一个名为myList的列表,其中包含许多数据框,例如myDF1myDF2等等),并且eval(parse(text=paste0(myList$myDF, "index")))对我很有效。谢谢! - Serendipity
11
eval(as.name(CHARACTER_HERE)) 对我有用,希望能帮到其他人。 (说明:该代码片段是R语言中的一行代码) - Jacques Mathieu

40
标题中问题的基本答案是使用Josh O'Brien所提出的eval(as.symbol(variable_name_as_string)), 如下所示。
var.name = "x"
assign(var.name, 5)
eval(as.symbol(var.name)) # outputs 5

更简单地说:
get(var.name) # 5

1
你应该得到一枚奖牌。我已经尝试了很多方法来解决这个问题,而你告诉我有一个叫做“get”的函数。7年后,仍然非常有帮助! - Mark

11

没有任何示例数据,确实很难知道你想要的是什么。例如,我完全无法猜测你的对象 set(或者是 sets)长什么样。

就此而言,以下内容是否有所帮助?

set1 <- data.frame(x = 4:6, y = 6:4, z = c(1, 3, 5))

plot(1:10, type="n")
XX <- "set1"
with(eval(as.symbol(XX)), symbols(x, y, circles = z, add=TRUE))

编辑:

现在我看到你的真正任务了,这是一行代码,可以实现你想要的所有功能,而不需要任何for()循环:

with(dat, symbols(sq, cu, circles = num,
                  bg = c("red", "blue")[(num>5) + 1]))

可能让人感到奇怪的是指定背景颜色的代码。尝试使用以下两行代码,看看它是如何工作的:

c(TRUE, FALSE) + 1
# [1] 2 1
c("red", "blue")[c(F, F, T, T) + 1]
# [1] "red"  "red"  "blue" "blue"

我为您添加了一个样本数据集,但是您的示例有效。我不熟悉with的使用--它似乎为后续变量名称提供了一个框架。我成功地这样使用:for (i in 1:length(sets)) { with(eval(as.symbol(sets[[i]])), symbols(sq,cu,circles=num,bg=colors[[i]],add=T)) 谢谢! - Hendy
@Hendy -- 很高兴听到这个消息。我刚刚添加了一个一行代码,可能使您能够完全绘制整个图表,而无需使用subset()for()循环。祝你好运! - Josh O'Brien

9
如果你想要将一个字符串作为变量名使用,你可以使用assign方法:
var1="string_name"

assign(var1, c(5,4,5,6,7))

string_name 

[1] 5 4 5 6 7

3

对数据进行子集和合并是不必要的。同样,循环也不需要,因为这些操作都是向量化的。根据你之前的编辑,我猜测你正在做气泡图。如果是这样,下面的例子或许能够帮助你。如果完全错误,我可以删除这个回答。

library(ggplot2)
# let's look at the included dataset named trees.
# ?trees for a description
data(trees)
ggplot(trees,aes(Height,Volume)) + geom_point(aes(size=Girth))
# Great, now how do we color the bubbles by groups?
# For this example, I'll divide Volume into three groups: lo, med, high
trees$set[trees$Volume<=22.7]="lo"
trees$set[trees$Volume>22.7 & trees$Volume<=45.4]="med"
trees$set[trees$Volume>45.4]="high"

ggplot(trees,aes(Height,Volume,colour=set)) + geom_point(aes(size=Girth))


# Instead of just circles scaled by Girth, let's also change the symbol
ggplot(trees,aes(Height,Volume,colour=set)) + geom_point(aes(size=Girth,pch=set))

# Now let's choose a specific symbol for each set. Full list of symbols at ?pch
trees$symbol[trees$Volume<=22.7]=1
trees$symbol[trees$Volume>22.7 & trees$Volume<=45.4]=2
trees$symbol[trees$Volume>45.4]=3

ggplot(trees,aes(Height,Volume,colour=set)) + geom_point(aes(size=Girth,pch=symbol))

0

对我来说最好用的是同时使用quote()eval()

例如,让我们使用for循环打印每一列:

Columns <- names(dat)
for (i in 1:ncol(dat)){
  dat[, eval(quote(Columns[i]))] %>% print
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接