2013-02-11 40 views
3

这里有两种不同的方式,其中一个工作和一种不分配一个例子:分配给一个data.frame用`with`

library(datasets) 
dat <- as.data.frame(ChickWeight) 
dat$test1 <- with(dat, Time + weight) 
with(dat, test2 <- Time + weight) 
> colnames(dat) 
[1] "weight" "Time" "Chick" "Diet" "test1" 

我已经习惯了这种行为。也许更令人惊讶的是test2刚好消失(而不是在基础环境清盘,因为我预计):

> ls(pattern="test") 
character(0) 

注意的是一个相当简单的^ H^H^H^H^H^^ h短功能:

function (data, expr, ...) 
eval(substitute(expr), data, enclos = parent.frame()) 

首先,让我们用复制的功能:

eval(substitute(Time+weight), envir=dat, enclos=parent.frame()) 

现在用不同的机箱测试:

testEnv <- new.env() 
eval(substitute(test3 <- Time+weight), envir=dat, enclos=testEnv) 
ls(envir=testEnv) 

哪个仍然没有分配到任何地方。这反驳了我的预感,认为它与封闭的环境被抛弃有关,而是指向一些更基本的论点,而不是做我认为它的做法。

我很好奇力学为什么这是怎么回事,如果有一个替代允许转让。

+0

因为'dat'不是环境你的最后一个例子不修改'dat'。最好它会通过'as.environment'强制转换到一个环境,然后被修改,然后立即丢弃,因为没有其他引用,所以原来的'dat'保持不变。 – 2013-02-12 03:54:51

回答

4

变化with变为withinwith仅用于使变量可用,而不会改变它们。

编辑:为了详细说明,我相信withwithin都会创建一个新环境,并使用给定的类列表对象(如数据框)填充它,然后评估该环境中给定的表达式。不同之处在于with返回表达式的结果并放弃环境,而within返回环境(转换回原来的类,例如data.frame)。无论哪种方式,在表达式中进行的任何赋值大概都是在创建的环境中执行的,它被with丢弃。这解释了为什么test2在做with(dat, test2 <- Time + weight)后无处可寻。

请注意,由于within返回修改的环境而不是就地编辑它(即按值呼叫语义),因此您需要执行dat <- within(dat, test2 <- Time + weight)

如果您想要一个函数来分配当前环境(或任何指定的环境),请查看assign

编辑2:现代答案是拥抱tidyverse和使用magrittr & dplyr:

library(datasets) 
library(dplyr) 
library(magrittr) 
dat <- as.data.frame(ChickWeight) 
dat %<>% mutate(test1 = Time + weight) 

最后一行相当于

dat <- dat %>% mutate(test1 = Time + weight) 

这又相当于

dat <- mutate(dat, test1 = Time + weight) 

使用最后3行中的哪一行最有意义你。

+0

有帮助,但“内部”比'with'要少得多,我很好奇为什么有必要为它分配一个函数。具体而言,'within'通过'data [nl] < - l'分配给data.frame的特定列。没有'内部'方法分配给环境,但我想你可以直接使用'eval'来达到这个目的? – 2013-02-11 19:19:36

+0

这个建议是错误的。 “内部”不会分配给其环境以外的列。你需要做:'dat $ test2 < - 带(dat,时间+权重)'或'dat < - 带(dat,test2 < - 时间+权重)' – 2013-02-11 20:07:09

+0

是的,你是对的。我在手机上写下了我原来的答案,但无法充分阐述。 – 2013-02-11 20:14:08

1

的事实,在命令行下面的作品...

eval(substitute(test <- Time + weight, dat)) 

...我总结了以下,这似乎工作的启发。

myWith <- function(DAT, expr) { 
    X <- call("eval", 
       call("substitute", substitute(expr), DAT)) 
    eval(X, parent.frame()) 
} 

## Trying it out 
dat <- as.data.frame(ChickWeight) 
myWith(dat, test <- Time + weight) 
head(test) 
# [1] 42 53 63 70 84 103 

(这个问题的复杂的方面是我们需要substitute()搜索符号一个环境(当前帧),而“外” eval()分配成不同环境(父帧)。)

+1

我应该补充说*使用*一个执行非本地任务的函数,因为这是一个非常糟糕的主意,在我看来。仍然有趣的是,它可以完成。 – 2013-02-11 20:59:06

1

我知道这样做太复杂了。 withwithin都返回由数据框的命名列上的操作计算得出的值。如果您不将它们分配给任何内容,则该值将被垃圾收集。存储tehn的常用方法是使用<-运算符将对象分配给指定对象或可能的对象组件。 within返回整个数据帧,而with只返回从列名称上执行的任何操作计算出的向量。当然,您可以使用assign而不是<-,但我认为过度使用该函数可能会混淆而不是澄清代码。在使用中差别只是分配给一个数据帧entrire或只是一个栏:

dat <- within(dat, newcol <- oldcol1*oldcol2) 
dat$newcol <- with(dat, oldcol1*oldcol2)