我有:
z = data.frame(x1=a, x2=b, x3=c, etc)
我正在尝试:
for (i in 1:10)
{
paste(c('N'),i,sep="") -> paste(c('z$x'),i,sep="")
}
问题:
paste(c('z$x'),i,sep="")
会产生"z$x1", "z$x1"
而不是调用实际值。我需要表达式进行评估。我试过了as.numeric, eval
。似乎都没有效果。
paste(c('N'),i,sep="")
收益"N1", "N2"
。我需要将表达式仅用作名称。如果我尝试为其分配paste(c('N'),5,sep="") -> 5
,即"N5" -> 5
而不是N5 -> 5
,我会将分配目标扩展为非语言对象。
这项任务非常简单,因为我可以这样做:
N1 = x1 ...... N2 = x2 ......
等,但我想学习新的东西
答案 0 :(得分:2)
我建议使用类似for( i in 1:10 ) z[,i] <- N[,i]
...
但是,既然你说你想学习新的东西,你就可以使用parse
和substitute
。
注意:这些小工具很有趣,但有经验的用户(不是我)会避开它们。
这称为“计算语言”。它非常有趣,它有助于理解R的工作方式。让我试着介绍一下:
基本语言构造是一个常量,如数字或字符向量。它是微不足道的,因为它与它的“未评估”版本没有什么不同,但它是更复杂表达的构建块之一。
(官方)基本语言对象是symbol
,也称为name
。它只是指向另一个对象的指针,即标识可能存在或不存在的另一个对象的标记。例如,如果您运行x <- 10
,则x
是一个引用值10
的符号。换句话说,评估符号x
会产生数字向量10
。评估不存在的符号会产生错误。
符号看起来像字符串,但不是。您可以使用as.symbol("x")
将字符串转换为符号。
下一个语言对象是call
。这是一个递归对象,实现为list
,其元素是常量,符号或其他调用。第一个元素不必须是常量,因为它必须求值为将被调用的实际function
。其他元素是此函数的参数。
如果第一个参数未计算到现有函数,则R将抛出Error: attempt to apply non-function
或Error: could not find function "x"
(如果第一个参数是未定义的符号或指向函数以外的其他参数)
示例:代码行f(x, y+z, 2)
将被解析为4个元素的列表,第一个是f
(作为符号),第二个是x
(另一个符号),第三个是另一个call
,第四个是数字常量。第三个元素y+z
只是一个带有两个参数的函数,因此它会解析为三个名称的列表:'+'
,y
和z
。
最后,还有expression
对象,它是一个调用/符号/常量列表,用于逐个评估。
你会在这里找到很多信息:
https://github.com/hadley/devtools/wiki/Computing-on-the-language
好的,现在让我们回到你的问题: - )
你所尝试的东西不起作用,因为paste
的输出是一个字符串,并且赋值函数期望作为其第一个参数,评估为一个符号,可以创建或修改。或者,第一个参数也可以评估与替换函数关联的调用。这些有点棘手,但它们由赋值函数本身处理,而不是由解析器处理。
您看到的错误消息target of assignment expands to non-language object
由赋值函数触发,正是因为您的目标求值为字符串。
我们可以修复在正确的位置建立一个包含所需符号的呼叫。最“强力”的方法是将所有内容放在一个字符串中并使用解析:
parse(text=paste('N',i," -> ",'z$x',i,sep=""))
另一种方法是使用substitute
:
substitute(x -> y, list(x=as.symbol(paste("N",i,sep="")), y=substitute(z$w, list(w=paste("x",i,sep="")))))
内部替代品会创建call
s z$x1
,z$x2
等。外部替代品将此调用作为分配的标记,以及符号N1
,{ {1}}等作为值。
N2
会在parse
中生成expression
和substitute
。两者都可以传递给call
以获得相同的结果。
最后一点注意事项:我重申所有这些都是作为一个教学示例,以帮助理解语言的内部工作原理,但是从良好的编程习惯中远使用{{1 }和eval
,除非真的没有其他选择。
答案 1 :(得分:2)
data.frame
是named list
。这通常是一种很好的做法,并且惯用R-ish
不要在全局环境中拥有大量对象,而是在列表中包含相关(或类似)对象并使用lapply
等。
您可以使用list2env
将列表中的命名元素(data.frame中的列)多重分配到全局环境
DD <- data.frame(x = 1:3, y = letters[1:3], z = 3:1)
list2env(DD, envir = parent.frame())
## <environment: R_GlobalEnv>
## ta da, x, y and z now exist within the global environment
x
## [1] 1 2 3
y
## [1] a b c
## Levels: a b c
z
## [1] 3 2 1
答案 2 :(得分:1)
我不确定你想要完成什么。但这是一个猜测:
### Create a data.frame using the alphabet
data <- data.frame(x = 'a', y = 'b', z = 'c')
### Create a numerical index corresponding to the letter position in the alphabet
index <- which(tolower(letters[1:26]) == data[1, ])
### Use an 'lapply' to apply a function to every element in 'index'; creates a list
val <- lapply(index, function(x) {
paste('N', x, sep = '')
})
### Assign names to our list
names(val) <- names(data)
### Observe the result
val$x